//
//  KVStore.swift
//  Casecord
//
//  Created by baozi on 2024/1/3.
//

import Foundation
import UIKit
import MMKV
import HandyJSON

class KVStoreKey<T>: KVStoreKeys {}

class KVStoreKeys: RawRepresentable, Hashable {
    let rawValue: String
    
    required init!(rawValue: String) {
        self.rawValue = rawValue
    }
    
    convenience init(_ key: String) {
        self.init(rawValue: key)
    }
    var hashValue: Int {
        rawValue.hashValue
    }
}

struct KVStore {
    private init() {}
}

extension KVStore {
    
    // MARK: String
    static subscript(key: String) -> String? {
        get {
            MMKV.default()?.string(forKey: key)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key)
                return
            }
            MMKV.default()?.set(value, forKey: key)
        }
    }
    
    // MARK: String
    static subscript(key: String, userId: String) -> String? {
        get {
            MMKV(mmapID: userId)?.string(forKey: key)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key)
                return
            }
            MMKV(mmapID: userId)?.set(value, forKey: key)
        }
    }
    
    // MARK: String
    static subscript(key: KVStoreKey<String>) -> String? {
        get {
            MMKV.default()?.string(forKey: key.rawValue)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV.default()?.set(value, forKey: key.rawValue)
        }
    }
    // MARK: String
    static subscript(key: KVStoreKey<String>, userId: String) -> String? {
        get {
            MMKV(mmapID: userId)?.string(forKey: key.rawValue)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV(mmapID: userId)?.set(value, forKey: key.rawValue)
        }
    }
    // MARK: Bool
    static subscript(key: KVStoreKey<Bool>) -> Bool {
        get {
            MMKV.default()?.bool(forKey: key.rawValue) == true
        }
        set {
            MMKV.default()?.set(newValue, forKey: key.rawValue)
        }
    }
    // MARK: Bool
    static subscript(key: KVStoreKey<Bool>, default: Bool) -> Bool {
        get {
            MMKV.default()?.bool(forKey: key.rawValue) ?? `default`
        }
        set {
            MMKV.default()?.set(newValue, forKey: key.rawValue)
        }
    }
    // MARK: Bool
    static subscript(key: KVStoreKey<Bool>, userId: String) -> Bool {
        get {
            MMKV(mmapID: userId)?.bool(forKey: key.rawValue) ?? false
        }
        set {
            MMKV(mmapID: userId)?.set(newValue, forKey: key.rawValue)
        }
    }
    // MARK: Date
    static subscript(key: KVStoreKey<Date>) -> Date? {
        get {
            MMKV.default()?.date(forKey: key.rawValue)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV.default()?.set(value, forKey: key.rawValue)
        }
    }
    // MARK: Date
    static subscript(key: KVStoreKey<Date>, userId: String) -> Date? {
        get {
            MMKV(mmapID: userId)?.date(forKey: key.rawValue)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV(mmapID: userId)?.set(value, forKey: key.rawValue)
        }
    }
    // MARK: Int
    static subscript(key: KVStoreKey<Int>) -> Int? {
        get {
            if let int64 = MMKV.default()?.int64(forKey: key.rawValue) {
                return Int(exactly: int64)
            }
            return nil
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            if let int64 = Int64(exactly: value) {
                MMKV.default()?.set(int64, forKey: key.rawValue)
            } else if let int32 = Int32(exactly: value) {
                MMKV.default()?.set(int32, forKey: key.rawValue)
            }
        }
    }
    
    // MARK: Int
    static subscript(key: KVStoreKey<Int>, userId: String) -> Int? {
        get {
            guard let value = MMKV(mmapID: userId)?.int64(forKey: key.rawValue) else {
                return nil
            }
            return Int(exactly: value)
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            if let int64 = Int64(exactly: value) {
                MMKV(mmapID: userId)?.set(int64, forKey: key.rawValue)
            } else if let int32 = Int32(exactly: value) {
                MMKV(mmapID: userId)?.set(int32, forKey: key.rawValue)
            }
        }
    }
    
    // MARK: Int64
    static subscript(key: KVStoreKey<Int64>) -> Int64? {
        get {
            guard let value = MMKV.default()?.int64(forKey: key.rawValue) else {
                return nil
            }
            return value
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV.default()?.set(value, forKey: key.rawValue)
        }
    }
    
    // MARK: Int64
    static subscript(key: KVStoreKey<Int64>, userId: String) -> Int64? {
        get {
            guard let value = MMKV(mmapID: userId)?.int64(forKey: key.rawValue) else {
                return nil
            }
            return value
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            MMKV(mmapID: userId)?.set(value, forKey: key.rawValue)
        }
    }
    
    static subscript(key: KVStoreKey<[AnyHashable: Any]>) -> [AnyHashable: Any]? {
        get {
            MMKV.default()?.object(of: NSDictionary.self, forKey: key.rawValue) as? [AnyHashable: Any]
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            let dict = NSDictionary.init(dictionary: value)
            MMKV.default()?.set(dict, forKey: key.rawValue)
        }
    }

    static subscript(key: KVStoreKey<[AnyHashable: Any]>, userId: String) -> [AnyHashable: Any]? {
        get {
            MMKV(mmapID: userId)?.object(of: NSDictionary.self, forKey: key.rawValue) as? [AnyHashable: Any]
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            let dict = NSDictionary.init(dictionary: value)
            MMKV(mmapID: userId)?.set(dict, forKey: key.rawValue)
        }
    }

    static subscript(key: KVStoreKey<[String: Any]>) -> [String: Any]? {
        get {
            MMKV.default()?.object(of: NSDictionary.self, forKey: key.rawValue) as? [String: Any]
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV.default()?.removeValue(forKey: key.rawValue)
                return
            }
            let dict = NSDictionary.init(dictionary: value)
            MMKV.default()?.set(dict, forKey: key.rawValue)
        }
    }

    static subscript(key: KVStoreKey<[String: Any]>, userId: String) -> [String: Any]? {
        get {
            MMKV(mmapID: userId)?.object(of: NSDictionary.self, forKey: key.rawValue) as? [String: Any]
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            let dict = NSDictionary.init(dictionary: value)
            
            MMKV(mmapID: userId)?.set(dict, forKey: key.rawValue)
        }
    }
    
    static subscript(key: KVStoreKey<Double>, default: Double) -> Double {
        get {
            MMKV.default()?.double(forKey: key.rawValue) ?? `default`
        }
        set {
            MMKV.default()?.set(newValue, forKey: key.rawValue)
        }
    }
    
    static subscript<T: Codable>(key: KVStoreKey<T>) -> T? {
        get {
            if let data = MMKV.default()?.data(forKey: key.rawValue) {
                do {
                    let v = try JSONDecoder().decode(T.self, from: data)
                    return v
                } catch {
                    return nil
                }
            } else {
                return nil
            }
        }
        set {
            if let v = try? JSONEncoder().encode(newValue) {
                MMKV.default()?.set(v, forKey: key.rawValue)
            }
        }
    }
    
    static subscript<T: HandyJSON>(key: KVStoreKey<T>) -> T? {
        get {
            if let dict = MMKV.default()?.object(of: NSDictionary.self, forKey: key.rawValue) as? [String: Any] {
                return T.deserialize(from: dict)
            } else {
                return nil
            }
        }
        set {
            if let v = newValue {
                if let v = v.toJSON() {
                    let dict = NSDictionary.init(dictionary: v)
                    MMKV.default()?.set(dict, forKey: key.rawValue)
                } else {
                    PPErrorLog("数据解析失败了， 有大问题")
                    MMKV.default()?.removeValue(forKey: key.rawValue)
                }
            } else {
                MMKV.default()?.removeValue(forKey: key.rawValue)
            }
        }
    }
    
    static subscript<T: HandyJSON>(key: KVStoreKey<T>, userId: String) -> T? {
        get {
            if let dict = MMKV(mmapID: userId)?.object(of: NSDictionary.self, forKey: key.rawValue) as? [String: Any] {
                return T.deserialize(from: dict)
            } else {
                return nil
            }
        }
        set {
            guard let value = newValue else { // nil == remove value
                MMKV(mmapID: userId)?.removeValue(forKey: key.rawValue)
                return
            }
            if let v = value.toJSON() {
                let dict = NSDictionary.init(dictionary: v)
                MMKV(mmapID: userId)?.set(dict, forKey: key.rawValue)
            } else {
                PPErrorLog("解析失败了!")
            }
        }
    }
//    static func clearCurrentUser() {
//        if let userId = User.loginer?.userId {
//            MMKV(mmapID: userId)?.clearAll()
//            Toast("清除成功").show()
//        }
//    }
//    static func clearAll() {
//        MMKV.default()?.clearAll()
//        Toast("清除成功").show()
//    }
}

extension KVStoreKey where T == Bool {
    
    func toggle() {
        KVStore[self] = !KVStore[self]
    }
    
}
